import java.applet.Applet;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;

import javax.swing.JFrame;
import javax.swing.JOptionPane;

/**
 * Driver class that runs the game. It creates objects for the
 * gameConfigurationScreen. It keeps track to see if the user has inputed all
 * the necessary values in the gameConfigurationScreen. Then, this method gets
 * the appropriate values for the player's data (their name, race and color). It
 * then creates a player object with these values. Next, the game asks the user
 * to select their property. (this is the same for all the other players). If an
 * appropriate piece of land is selected, the game places a colored block (this
 * color is the user's original color selection in the setup screen) on that
 * plot. Once every player takes their turns, the game moves onto the second
 * round. During each round, the players have the option to skip their turn or
 * visit the store (land office, pub etc). The game ends when all players play
 * through 12 rounds. The code also takes in vital information about the store,
 * players and land and writes them in the savedGame.ser file
 * 
 * @author GT Five-O
 * @version v1.0b
 * 
 */
public class GameEngine extends Applet implements java.io.Serializable {

    private static final long serialVersionUID = 1L;
    private static RandomEvent randEvent;
    private static Player[] players;
    private static Integer[] foodReq = GameConstants.FOOD_REQUIREMENTS;
    private static GameScreen board;
    private static int roundCounter;
    private static int roundCounterDisplay;
    private static String map;

    /**
     * Main Method
     * 
     * @param args
     */
    public static void main(String[] args) {

        /** show pop up screen */

        JFrame frame = new JFrame();

        Object[] options = { "Cancel", "Load Game", "New Game" };
        int n = JOptionPane.showOptionDialog(frame, "Please select an option:",
                "Choose Game Mode", JOptionPane.YES_NO_CANCEL_OPTION,
                JOptionPane.QUESTION_MESSAGE, null, options, options[2]);

        frame.dispose();

        if (n == 0) {
            System.exit(0);
        } else if (n == 1) { // load game

            Store importedStore;
            LinkedList<IDAssociator> importedMuleIcons;
            LinkedList<IDAssociator> importedPropIcons;

            LinkedList<IDAssociator> muleIcons = new LinkedList<IDAssociator>();
            LinkedList<IDAssociator> propIcons = new LinkedList<IDAssociator>();

            try {
                FileInputStream fileIn = new FileInputStream(
                        "/tmp/savedGame.ser");
                @SuppressWarnings("resource")
                ObjectInputStream in = new ObjectInputStream(fileIn);
                players = (Player[]) in.readObject();
                String map = (String) in.readObject();
                board = new GameScreen(players, map);
                importedStore = (Store) in.readObject();
                importedMuleIcons = (LinkedList<IDAssociator>) in.readObject();
                importedPropIcons = (LinkedList<IDAssociator>) in.readObject();

                /** FOR IMPORTING MULE IOCONS */
                for (IDAssociator i : importedPropIcons) {
                    propIcons.add(new IDAssociator(i.getID(), i.getX(), i
                            .getY(), i.getWidth(), i.getHeight(), board
                            .getPane(), false));

                    String color = "";

                    for (Player p : players) {
                        for (Property prop : p.getProperties()) {
                            if (prop.getPropertyID() == propIcons.getLast()
                                    .getID()) {
                                color = p.getPlayerColor();
                                break;
                            }
                        }
                    }

                    if (color.equals("Red")) {
                        propIcons.getLast().setJLabelIcon(
                                "Images/PlayerColorIcons/red.png");
                    } else if (color.equals("Black")) {
                        propIcons.getLast().setJLabelIcon(
                                "Images/PlayerColorIcons/black.png");
                    } else if (color.equals("Green")) {
                        propIcons.getLast().setJLabelIcon(
                                "Images/PlayerColorIcons/green.png");
                    } else {
                        propIcons.getLast().setJLabelIcon(
                                "Images/PlayerColorIcons/yellow.png");
                    }
                }

                /** FOR IMPORTING MULE IOCONS */
                for (IDAssociator i : importedMuleIcons) {
                    muleIcons.add(new IDAssociator(i.getID(), i.getX(), i
                            .getY(), i.getWidth(), i.getHeight(), board
                            .getPane(), true));
                    muleIcons.getLast().setJLabelIcon(i.getIcon());
                }

                roundCounter = (Integer) in.readObject();
                roundCounterDisplay = (Integer) in.readObject();
                setChosenPropData((ArrayList<String>) in.readObject());
            } catch (IOException i) {
                JOptionPane
                .showMessageDialog(
                        frame,
                        "Oops! Either you don't have a game to load or we couldn't find your saved game.");
                System.exit(0);
                i.printStackTrace();
                return;
            } catch (ClassNotFoundException c) {
                JOptionPane
                .showMessageDialog(
                        frame,
                        "Oops! Either you don't have a game to load or we couldn't find your saved game.");
                System.exit(0);
                c.printStackTrace();
                return;
            }

            board.setMuleLabels(muleIcons);
            board.setPropLabels(propIcons);
            board.setStore(importedStore);
            board.setVisible(true);
            board.setGrant(false);
            board.setAllowed(false);
            randEvent = new RandomEvent(board);

        } else if (n == 2) {
            /** New GAME */

            gameConfigurationScreen gameInit = new gameConfigurationScreen();
            gameInit.setVisible(true);

            boolean flag = true;
            while (flag) {
                if (!gameInit.isVisible()) {
                    flag = gameInit.isNotFinished();
                }
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            ArrayList<String[]> playerData = gameInit.getPlayerData();

            players = new Player[playerData.size()];

            for (int i = 0; i < playerData.size(); i++) {
                String name = playerData.get(i)[0];
                String race = playerData.get(i)[1];
                String color = playerData.get(i)[2];
                String level = playerData.get(i)[3];
                players[i] = new Player(name, race, color, i, level);
                players[i].setScore();
            }

            map = gameInit.getMapSelected();
            
            // determine type of map
            if (map.equals("Standard")) {
                map = "board.jpg";
                System.out.println("Here1");
            } else if (map.equals("Bikini Bottom")) {
                map = "bikini-bottom.jpg";
                System.out.println("Here2");
            } else {
                System.out.println("Here3");
                map = "board.jpg";
            }
            
            System.out.println("Map is: " + map);

            board = new GameScreen(players, map);
            board.setVisible(true);
            randEvent = new RandomEvent(board);

            /** Land Selection Phase */

            JOptionPane.showMessageDialog(board,
                    "Land Grant Property Selection Round!");

            int passed = 0;
            boolean landSelection = true;
            while (landSelection) {
                for (Player p : players) {
                    board.setAllowed(true);
                    board.setCurrent(p);
                    JOptionPane
                    .showMessageDialog(
                            board,
                            "Player "
                                    + p.getPlayerName()
                                    + " please select your first property by clicking on it! or Press ENTER to pass your turn");

                    board.focusPane();
                    boolean proceed = false;
                    while (!proceed) {
                        try {
                            Thread.sleep(500);
                            if (board.landSelected()) {
                                board.setLandColor(p.getPlayerColor());
                                proceed = true;
                                board.setSelected(false);
                            } else if (board.passed()) {
                                proceed = true;
                                board.setPassed(false);
                                passed++;
                            }
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
                landSelection = false;
            }
            landSelection = true;
            /**
             * If both players didn't pass, then continue onto second round of
             * land selection
             */
            if (passed != players.length) {
                JOptionPane.showMessageDialog(board,
                        "Round 2 of Land Selection.");
                while (landSelection) {
                    for (Player p : players) {
                        board.setCurrent(p);
                        board.setAllowed(true);
                        JOptionPane
                        .showMessageDialog(
                                board,
                                "Player "
                                        + p.getPlayerName()
                                        + " please select your second property by clicking on it! or Press ENTER to pass your turn");
                        board.focusPane();
                        boolean proceed = false;
                        while (!proceed) {
                            try {
                                Thread.sleep(500);
                                if (board.landSelected()) {
                                    board.setLandColor(p.getPlayerColor());
                                    proceed = true;
                                    board.setSelected(false);
                                } else if (board.passed()) {
                                    proceed = true;
                                    board.setPassed(false);
                                }
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                    landSelection = false;
                }
            }
            board.setGrant(false);
            board.setAllowed(false);
            JOptionPane.showMessageDialog(board, "Land Grant Phase Complete!");

            roundCounter = 0;
            roundCounterDisplay = 0;

        }

        /**
         * GENERAL ROUNDS START
         */
        board.setCurrent(players[0]);
        boolean gameFinish = false;
        boolean doneSort = false;
        while (roundCounter != GameConstants.ROUNDS) {

            board.setRoundNum((roundCounterDisplay + 1) + "");

            try {
                FileOutputStream fileOut = new FileOutputStream(
                        "/tmp/savedGame.ser");
                ObjectOutputStream out = new ObjectOutputStream(fileOut);
                // out.writeObject(board);
                out.writeObject(getPlayerSave());
                out.writeObject(map);
                out.writeObject(getStoreSave());
                out.writeObject(getMuleSave());
                out.writeObject(getPropSave());
                out.writeObject(roundCounter);
                out.writeObject(roundCounterDisplay);
                out.writeObject(getChosenPropSave());
                out.close();
                fileOut.close();
                System.out
                .printf("Serialized data is saved in /tmp/savedGame.ser");
            } catch (IOException i) {
                i.printStackTrace();
            }

            Long init = System.currentTimeMillis();
            Long fin = System.currentTimeMillis();
            Long total = fin - init;
            Long messageTime = (long) GameConstants.MESSAGE_SHOW_TIME;

            /**
             * SORT PLAYERS (BY SCORE)
             */
            Player[] sortPlayers = players.clone();
            Arrays.sort(sortPlayers);

            for (Player p : sortPlayers) {
                p.updateResources();
                board.updateInfoPanel();
                board.setCurrent(p);
                init = p.currentTime();
                total = p.currentTime() - init;
                p.setRound(roundCounter);
                board.setTimer("...");

                board.coverGameScreen();

                Long timerTime = (long) p.getTime(foodReq[roundCounter]);
                for (int i = 0; i < foodReq[roundCounter]; i++) {
                    p.removeFood();
                }
                while (total <= messageTime) {
                    fin = p.currentTime();
                    total = fin - init;
                    Long mynum = messageTime - total;
                    String output = "<html><p style=\"color:#1b89a0;font-size:14px;\">Player "
                            + p.getPlayerName()
                            + " your turn starts in "
                            + (int) ((mynum * .001) + 1)
                            + " seconds.</p></html>";
                    board.setGameScreenCoverText(output);
                }
                board.uncoverGameScreen();
                if (p.equals(sortPlayers[0])) {
                    String message = randEvent.checkRandom(roundCounter, true);
                    if (message.equals("")) {
                    } else {
                        JOptionPane.showMessageDialog(board, message);
                    }
                    board.updateInfoPanel();
                } else {
                    String message = randEvent.checkRandom(roundCounter, false);
                    if (message.equals("")) {
                    } else {
                        JOptionPane.showMessageDialog(board, message);
                    }
                    board.updateInfoPanel();
                }
                board.setMessage("");
                p.storeInit(System.currentTimeMillis());
                fin = p.currentTime();
                p.setTimer(fin - p.getInit());
                board.uncoverGameScreen();
                boolean pturn = true;
                board.activatePub();
                while (p.roundCheck() && pturn) {
                    board.setCurrent(p);
                    pturn = board.getPubStatus();
                    fin = p.currentTime();
                    p.setTimer(fin - p.getInit());
                    total = fin - p.getInit();
                    Long mynum = timerTime - total;
                    board.setTimer("" + (int) ((mynum * .001) + 1));
                }
                p.storeInit(System.currentTimeMillis());
                fin = p.currentTime();
                p.setTimer(fin - p.getInit());
                p.setScore();
            }
            roundCounter++;
            roundCounterDisplay++;
        }
        /*
         * Game is completed!
         */
        System.exit(0);
    }

    /**
     * getter for the array of players during game save state
     * 
     * @return
     */
    public static Player[] getPlayerSave() {
        return players;
    }

    /**
     * getter for the store during game save state
     * 
     * @return
     */
    public static Store getStoreSave() {
        return board.getStore();
    }

    /**
     * gets the chosen data from the board
     * 
     * @return chosen
     */
    public static ArrayList<String> getChosenPropSave() {
        return board.getChosenSave();
    }

    /**
     * sets the chosen properties data from the save file in the GameBoard
     * 
     * @param data
     */
    public static void setChosenPropData(ArrayList<String> data) {
        board.setChosenData(data);
    }

    /**
     * getter for the mules during game save state
     * 
     * @return
     */
    public static LinkedList<IDAssociator> getMuleSave() {
        return board.getMuleLabel();
    }

    /**
     * getter for the land ownership during game save state
     * 
     * @return
     */
    public static LinkedList<IDAssociator> getPropSave() {
        return board.getownedPropLabel();
    }

}
